package response

import (
	"fmt"

	"github.com/go-playground/validator/v10"
	"github.com/kataras/iris/v12"
)

const (
	Success           = 200
	SuccessNotContent = 204
	InernalError      = 500
	BadRequestError   = 400
)

type BaseResponse struct {
	Code    int    `json:"code"`
	Status  string `json:"status"`
	Data    any    `json:"data,omitempty"`
	Message string `json:"message"`
	Error   string `json:"error,omitempty"`
}

type PageResponse struct {
	BaseResponse
	Total int `json:"total"`
}

type validationError struct {
	ActualTag string `json:"tag"`
	Namespace string `json:"namespace"`
	Kind      string `json:"kind"`
	Type      string `json:"type"`
	Value     string `json:"value"`
	Param     string `json:"param"`
}

func JsonSuccess(ctx iris.Context, data any) {
	ctx.JSON(
		BaseResponse{
			Code:    Success,
			Status:  "success",
			Data:    data,
			Message: "操作成功",
		},
	)
}

func JsonMsg(ctx iris.Context, msg string) {
	ctx.JSON(
		BaseResponse{
			Code:    Success,
			Status:  "success",
			Message: msg,
		},
	)
}

func JsonError(ctx iris.Context, err error) {

	var errJson = err
	var code = InernalError
	if ctx.IsDebug() {
		if errs, ok := err.(validator.ValidationErrors); ok {

			validationErrors := wrapValidationErrors(errs)

			errJson = iris.NewProblem().
				Title("Validation error").
				Detail("One or more fields failed to be validated").
				Type("/user/validation-errors").
				Key("errors", validationErrors)
			code = BadRequestError
		}
	}
	resp := BaseResponse{
		Code:   code,
		Status: "error",
		Error:  errJson.Error(),
	}

	ctx.StatusCode(InernalError)
	ctx.JSON(resp)
}

func JSONPagination(ctx iris.Context, data any, total int) {
	ctx.JSON(PageResponse{
		BaseResponse: BaseResponse{
			Code:    Success,
			Status:  "success",
			Message: "查询成功",
			Data:    data,
		},

		Total: total,
	})
}

func wrapValidationErrors(errs validator.ValidationErrors) []validationError {
	validationErrors := make([]validationError, len(errs))
	for _, validationErr := range errs {
		validationErrors = append(validationErrors, validationError{
			ActualTag: validationErr.ActualTag(),
			Namespace: validationErr.Namespace(),
			Kind:      validationErr.Kind().String(),
			Type:      validationErr.Type().String(),
			Value:     fmt.Sprintf("%v", validationErr.Value()),
			Param:     validationErr.Param(),
		})
	}
	return validationErrors
}
